package evaluation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/* Class to get results from Yahoo/Bing API for web reinforcement
 * Gets results from server in XML format
 * Based on example from 
 * http://www.bing.com/community/site_blogs/b/developer/archive/2009/05/28/using-the-api-version-2-0-beta-with-java-and-the-api-s-xml-interface.aspx 
 */
public class BingSearcher {
	static XPathFactory factory = null;
	static XPath xpath = null;
	static XPathExpression expr = null;

	/*
	 * Builds URL of search query to retrieve results from the Server
	 */
	public static String BuildRequest(String queryString, int numResults) {
		// Replace the following string with the Bing AppId
		// Currently, there is no upper limit for API based search
		String AppId = "72FB1FE5709E2648BE1B83CB23C8E9D6D8C13F54";
		String requestString = "http://api.search.live.net/xml.aspx?"

		// Common request fields (required)
				+ "AppId=" + AppId + "&Query=" + queryString + "&Sources=Web"

				// Common request fields (optional)
				// + "&Version=2.0"
				// + "&Market=en-us"
				// + "&Adult=Moderate"

				// Web-specific request fields (optional)
				+ "&Web.Count=" + numResults
		// + "&Web.Offset=0"
		// + "&Web.FileType=DOC"
		// + "&Web.Options=DisableHostCollapsing+DisableQueryAlterations"
		;
		// System.out.println(requestString);
		return requestString;
	}

	public static Document GetResponse(String requestURL)
			throws ParserConfigurationException, SAXException, IOException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setNamespaceAware(true);
		Document doc = null;
		DocumentBuilder db = dbf.newDocumentBuilder();

		if (db != null) {
			// System.out.println(requestURL);
			doc = db.parse(requestURL);
		}

		return doc;
	}

	public static List<String> DisplayResponse(Document doc)
			throws XPathExpressionException {
		factory = XPathFactory.newInstance();
		xpath = factory.newXPath();
		xpath.setNamespaceContext(new APINameSpaceContext());
		NodeList errors = (NodeList) xpath.evaluate("//api:Error", doc,
				XPathConstants.NODESET);

		if (errors != null && errors.getLength() > 0) {
			// There are errors in the response. Display error details.
			DisplayErrors(errors);
		} else {
			return DisplayResults(doc);
		}
		return DisplayResults(doc);
	}

	/*
	 * Parses XML results and returns Answer Snippets as a List of Strings
	 */
	private static List<String> DisplayResults(Document doc)
			throws XPathExpressionException {
		String searchTerms = (String) xpath.evaluate("//api:SearchTerms", doc,
				XPathConstants.STRING);
		int total = Integer.parseInt((String) xpath.evaluate(
				"//web:Web/web:Total", doc, XPathConstants.STRING));
		System.out.println("Contains " + total + " webpages");
		int offset = Integer.parseInt((String) xpath.evaluate(
				"//web:Web/web:Offset", doc, XPathConstants.STRING));
		NodeList results = (NodeList) xpath.evaluate(
				"//web:Web/web:Results/web:WebResult", doc,
				XPathConstants.NODESET);

		// Display the results header.
		System.out.println("Web results for " + searchTerms);
		System.out.println("Retrieved " + (offset + results.getLength())
				+ " out of " + total + " possible web results ");
		System.out.println();

		// Display the Web results.
		StringBuilder builder = new StringBuilder();

		List<String> data = new ArrayList<String>();

		for (int i = 0; i < results.getLength(); i++) {
			String tmp = "";
			NodeList childNodes = results.item(i).getChildNodes();

			for (int j = 0; j < childNodes.getLength(); j++) {
				String fieldName = childNodes.item(j).getLocalName();

				if (fieldName.equalsIgnoreCase("Title")
						|| fieldName.equalsIgnoreCase("Description")) {
					builder.append(childNodes.item(j).getTextContent());
					tmp = tmp + childNodes.item(j).getTextContent() + "\n";
					builder.append("\n");
				}
			}
			data.add(tmp);
			builder.append("\n");
		}

		return data;
	}

	public static long getTotalNum(Document doc) throws NumberFormatException,
			XPathExpressionException {

		if (xpath == null) {
			factory = XPathFactory.newInstance();
			xpath = factory.newXPath();
			xpath.setNamespaceContext(new APINameSpaceContext());
		}
		String s = (String) xpath.evaluate("//web:Web/web:Total", doc,
				XPathConstants.STRING);
		//System.out.println(s);
		return Long.parseLong(s);
	}

	/*
	 * Displays error
	 */
	private static void DisplayErrors(NodeList errors) {
		System.out.println("Errors in API Errors:");
		System.out.println();

		for (int i = 0; i < errors.getLength(); i++) {
			NodeList childNodes = errors.item(i).getChildNodes();
			for (int j = 0; j < childNodes.getLength(); j++) {
				System.out.println(childNodes.item(j).getLocalName() + ":"
						+ childNodes.item(j).getTextContent());
			}
			System.out.println();
		}
	}

	public static long getWebPageNumber(String queryString) throws Exception {
		String requestURL = BingSearcher.BuildRequest(queryString + " -trec",
				10);
		// System.out.println("--"+requestURL);
		Document doc = BingSearcher.GetResponse(requestURL);
		// System.out.println(doc.toString());
		if (doc == null)
			System.out.println("no result");
		return BingSearcher.getTotalNum(doc);
	}
}
